package br.com.lambdacore.lang;

import br.com.lambdacore.collection.MapUtil;
import br.com.lambdacore.lang.annotation.Equals;
import br.com.lambdacore.lang.reflect.AnnotationUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import static br.com.lambdacore.validator.Validator.is;

class EqualsBuilder extends org.apache.commons.lang.builder.EqualsBuilder {

	private Map<Field, Object> equalsFields = MapUtil.hashMap();
	private Map<Method, Object> equalsMethods = MapUtil.hashMap();

	private Object thiz;

	private EqualsBuilder(Object thiz) {
		this.init(thiz);
	}

	@Override
	public boolean equals(Object other) {
		if (is(other).nil()) {
			return false;
		}
		if (other == this) {
			return true;
		}
		if (is(this.getThiz().getClass()).notInstanceOf(other.getClass())) {
			return false;
		}
		try {
			Set<Field> fields = this.equalsFields.keySet();
			for (Field field : fields) {
				this.append(this.equalsFields.get(field), field.get(other));
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return this.isEquals();
	}

	private Object getThiz() {
		return this.thiz;
	}

	@SuppressWarnings("unchecked")
	private void init(Object thiz) {
		this.setThiz(thiz);
		try {
			Collection<Field> fields = AnnotationUtils.getAllFieldsAnnoted(
					thiz.getClass(), Equals.class);
			for (Field field : fields) {
				field.setAccessible(true);
				this.equalsFields.put(field, field.get(this.getThiz()));
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private void setThiz(Object thiz) {
		this.thiz = thiz;
	}

	protected static EqualsBuilder newInstance(Object thiz) {
		return new EqualsBuilder(thiz);
	}

}
